﻿/*
 
Celerity: Sensory Overload
Copright 2012 by Adam Hill, David Gannon, Thomas Tamblyn & Patrick Ytting
Contact: adam.hill@outlook.com
Website: adamhill.org
Licence: MS-Pl Licence
  
 */

namespace Celerity.World
{
    using Celerity.Audio;
    using Celerity.Input;
    using Celerity.Logic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.Graphics;
    using System;
	using Particles;

    /// <summary>
    /// Responsible for managing the game world
    /// </summary>
    public class WorldModule
    {
        // Base game objects
        GraphicsDeviceManager graphics;
        //SpriteBatch spriteBatch;
        Vector3 headPos;
        InputModule input;
        GameLogic logic;
        ObstacleManager obstacle;
		CollisionDetector collision;
		ParticleFactory particleFactory;
		EmitterFactory emitter;

        // Public properties
        public Matrix world;
        public Matrix projection;
        public Camera camera;
        public Vector3 up;
        public Vector3 forward;
        public float farClip;

        // Triangles
        Effect tunnelEffect;
        Texture2D tunnelTexture;

        // The Game Tunnel
        Tunnel tunnel;

        // Player
        PlayerShip player;
        Model ship;
        float playerDistance;

		//particles
		Effect particleEffect;

        // Audio
        AudioModule audio;

        public WorldModule(GraphicsDeviceManager graphics,
                            AudioModule audio, 
                            InputModule input, 
                            GameLogic logic)
        {
            this.graphics = graphics;
            this.audio = audio;
            this.input = input;
            this.logic = logic;
        }

        public void Load(ContentManager content)
        {
            tunnelEffect = content.Load<Effect>("shader");
            tunnelTexture = Celerity.Content.ImageLibrary.TunnelTexture;
            ship = content.Load<Model>("ship");
			particleEffect = content.Load<Effect>("ParticleEffect");
        }

        public void Initialize()
        {
            farClip = 400.0f;
            up = new Vector3(0.0f, 1.0f, 0.0f);
            forward = new Vector3(0.0f, 0.0f, 1.0f);
            world = Matrix.CreateWorld(Vector3.Zero, forward, up);
            camera = new Camera(Matrix.CreateLookAt(Vector3.Zero, forward, up));
            projection = new Matrix();
            Matrix.CreatePerspectiveFieldOfView((float)Math.PI / 4.0f, graphics.GraphicsDevice.Viewport.AspectRatio, 0.01f, farClip, out projection);
            tunnel = new Tunnel(32, tunnelEffect, tunnelTexture);
            player = new PlayerShip(ship, logic);
            playerDistance = 11.0f;
			particleFactory = new ParticleFactory(graphics, particleEffect);
			emitter = new EmitterFactory(particleFactory);
			obstacle = new ObstacleManager(tunnelEffect, tunnel.CellSize, tunnel.numSegments, tunnel, logic, emitter);
			collision = new CollisionDetector(player.angle, playerDistance, 0.3f, 1.2f, tunnel, obstacle, emitter, logic);
        }

        public void Update(GameTime gameTime, Vector3 headPos, float chaosFactor)
        {
            this.headPos.X = headPos.X;
            this.headPos.Y = headPos.Y;
            this.headPos.Z = headPos.Z;
			obstacle.Update(gameTime, tunnel, chaosFactor);
			collision.Update(gameTime, player.angle, obstacle);
			tunnel.Update(gameTime, chaosFactor);
            player.Update(gameTime, tunnel.GetTunnelCentrePos(playerDistance), Tunnel.GetTunnelDirection(tunnel.CurrentPhase + playerDistance), input.playerJoystick, chaosFactor);
			camera.Update(gameTime, tunnel.CurrentPhase, this.headPos, player.angle);
			particleFactory.Update(gameTime, camera, tunnel.CurrentPhase);
			emitter.Update(gameTime);

        }

        public void Draw(GameTime gameTime)
        {
            tunnel.Draw(graphics, world, camera.view, projection, farClip);
            player.Draw(graphics, world, camera.view, projection);
			obstacle.Draw(graphics, world, camera.view, projection, farClip);
			particleFactory.Draw(graphics.GraphicsDevice, world, projection, camera);
        }
    }
}
